package tester

import (
	"fmt"

	"gitee.com/AlexWoo/arpc/alog"
)

const (
	stepErr = "error"
	stepEnd = "end"
)

var (
	defaultErrStep = &nextstep{stepName: stepErr}
	defaultEndStep = &nextstep{stepName: stepEnd}
)

type step struct {
	name string
	ms   msg       // msg step
	fs   flow      // flow step
	es   *nextstep // err step
}

func (st *step) run(t *tester) string {
	if st.ms != nil {
		if err := st.ms.run(t); err != nil {
			alog.LogError(t.lctx, "step[%s] ms.run error: %s", st.name, err.Error())
			return st.es.run(t)
		}
	}

	return st.fs.run(t)
}

//	{
//	  recv | send { ... }
//	  next: stepnext; | branch { ... }
//	  error: steperr;
//	}
func parseStep(name string, b []byte, start int) (int, *step, error) {
	st := &step{
		name: name,
	}

	var pr tokenResultType
	var token string
	var err error

	p := start
	last := len(b)

	for {
		if start == last {
			return p, nil, fmt.Errorf("conf end when parse step")
		}

		pr, p, token = readToken(b, start)
		switch pr {
		case block_start:
			switch token {
			case "recv":
				if st.ms != nil {
					return p, nil, fmt.Errorf("has more than one msg block")
				}

				start = p + 1

				p, st.ms, err = parseRecvMsg(b, start)
				if err != nil {
					return p, nil, err
				}

				start = p + 1
			case "send":
				if st.ms != nil {
					return p, nil, fmt.Errorf("has more than one msg block")
				}

				start = p + 1

				p, st.ms, err = parseSendMsg(b, start)
				if err != nil {
					return p, nil, err
				}

				start = p + 1
			case "branch":
				if st.fs != nil {
					return p, nil, fmt.Errorf("has more than one flow block")
				}

				start = p + 1

				p, st.fs, err = parseBranch(b, start)
				if err != nil {
					return p, nil, err
				}

				start = p + 1
			default:
				return p, nil, fmt.Errorf("unexpected block type %s", token)
			}

		case para_start:
			switch token {
			case "next":
				if st.fs != nil {
					return p, nil, fmt.Errorf("has more than one flow block")
				}

				start = p + 1

				p, st.fs, err = parseNext(b, start)
				if err != nil {
					return p, nil, err
				}

				start = p + 1
			case "error":
				if st.es != nil {
					return p, nil, fmt.Errorf("has more than one error block")
				}

				start = p + 1

				p, st.es, err = parseNext(b, start)
				if err != nil {
					return p, nil, err
				}

				start = p + 1
			default:
				return p, nil, fmt.Errorf("unexpected para type %s", token)
			}

		case block_end:
			if token != "" {
				return p, nil, fmt.Errorf("unexpected token type %s when parse step", pr)
			}

			if st.es == nil {
				st.es = defaultErrStep
			}

			return p, st, nil

		default:
			return p, nil, fmt.Errorf("unexpected token type %s when parse step", pr)
		}
	}
}
